home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / QuickDraw / Animation / SpriteMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  47.4 KB  |  2,177 lines  |  [TEXT/MPS ]

  1. /*
  2.  
  3.  
  4.     © Copyright 1991 Ricardo Batista,  All Rights Reserved.
  5.     
  6.     
  7.     Sprite Manager
  8.     
  9.     
  10.     04/20/91
  11.     
  12.     
  13.     HISTORY:  (Most Recent first)
  14.     
  15.     
  16.     04/20/91    rb    New today
  17.     
  18.     
  19. */
  20.  
  21.  
  22.  
  23.  
  24. #include <Types.h>
  25. #include <QuickDraw.h>
  26. #include <QDOffscreen.h>
  27. #include <Memory.h>
  28. #include <Resources.h>
  29. #include <OSUtils.h>
  30. #include <Retrace.h>
  31. #include <Windows.h>
  32. #include <ToolUtils.h>
  33.  
  34. #include "SpriteMgr.h"
  35.  
  36. #define        desiredPixSize        8
  37.  
  38. SpriteMgrRecPtr        Sprite_Mgr_Globals;        // global used to save our information
  39.  
  40.  
  41. pascal short SetDepth(GDHandle gd, short newDepth, short whichFlags, short newFlags) =
  42.                     {0x203C, 0x000A, 0x0013, 0xAAA2};
  43.  
  44. pascal short HasDepth(GDHandle gd, short newDepth, short whichFlags, short newFlags) =
  45.                     {0x203C, 0x000A, 0x0014, 0xAAA2};
  46.  
  47.  
  48.  
  49.  
  50.  
  51.     /*
  52.         This routine initializes the sprite manager, it must be called after dialogs,
  53.         windows, resources, and quickdraw have been initialized.  This routine creates
  54.         a record to memory to keep the sprite manager globals, it also finds the best
  55.         monitor in which to display the color animation and sets the monitor to 4 bit
  56.         color after saving the previous color depth.  This routine also installs a small
  57.         vbl task used by the drawing routines.
  58.         if cTable is not nil the given color table is made the current color table and the
  59.         previous color table saved for later restoration.
  60.         returns 0 if no error occured. 1 if no color monitor present or not enough memory
  61.         to create memory record.
  62.     */
  63.  
  64. short InitSpriteMgr(CTabHandle cTable)
  65. {
  66.     short err;
  67.     GDHandle device;
  68.     PixMapHandle pixH;
  69.     Boolean done = false;
  70.     short oldPixelSize;
  71.     CTabHandle    colorTable = 0L;
  72.     short mode;
  73.     
  74.     if (Sprite_Mgr_Globals)
  75.         return(0);
  76.     Sprite_Mgr_Globals = (SpriteMgrRecPtr) NewPtrClear(sizeof(SpriteMgrRec));
  77.     if (!Sprite_Mgr_Globals)
  78.         return(1);
  79.     device = GetDeviceList();
  80.     if (!device) {
  81.         DisposPtr((Ptr) Sprite_Mgr_Globals);
  82.         Sprite_Mgr_Globals = 0L;
  83.         return(1);
  84.     }
  85.     while (device && !done) {
  86.         pixH = (**device).gdPMap;
  87.         oldPixelSize = (**pixH).pixelSize;
  88.         if (oldPixelSize == desiredPixSize) {
  89.             if (cTable) {
  90.                 colorTable = (**pixH).pmTable;
  91.                 (**pixH).pmTable = cTable;
  92.                 GDeviceChanged(device);
  93.             }
  94.             done = true;
  95.         }
  96.         else {
  97.             mode = HasDepth(device, desiredPixSize, 1, 1);        /* color device */
  98.             if (mode) {
  99.                 err = SetDepth(device, desiredPixSize, 1, 1);
  100.                 if (cTable) {
  101.                     colorTable = (**pixH).pmTable;
  102.                     (**pixH).pmTable = cTable;
  103.                     GDeviceChanged(device);
  104.                 }
  105.                 done = true;
  106.             }
  107.         }
  108.         if (!done)
  109.             device = (GDHandle) (**device).gdNextGD;
  110.     }
  111.     if (!done)
  112.         return(1);
  113.     
  114.     Sprite_Mgr_Globals->originalCTable = colorTable;
  115.     Sprite_Mgr_Globals->currCTable = cTable;
  116.     Sprite_Mgr_Globals->originalDepth = oldPixelSize;
  117.     Sprite_Mgr_Globals->task.qType = vType;
  118.     Sprite_Mgr_Globals->task.vblAddr = (ProcPtr) VTASK;
  119.     Sprite_Mgr_Globals->task.vblCount = 1;
  120.     Sprite_Mgr_Globals->task.vblPhase = 0;
  121.     Sprite_Mgr_Globals->deviceUsed = device;
  122.     Sprite_Mgr_Globals->active = false;
  123.     Sprite_Mgr_Globals->changed = true;
  124.     Sprite_Mgr_Globals->updateRects = 0;
  125.     
  126.     err = VInstall((QElemPtr) &Sprite_Mgr_Globals->task.qLink);
  127.     return(err);
  128. }
  129.  
  130.     
  131.     
  132.     
  133.     
  134.     
  135.     
  136.     
  137.     
  138.     
  139.     
  140.     /*
  141.         This routine disposes of the window used by animation, destroys all of the graphic
  142.         worlds created and deinstalls the vbl task.  It also re-enables any applications
  143.         hidden by ActivateAnimation.
  144.         Restores the color table if it had been changed when InitSpriteMgr was called.
  145.         This routine should be called when the application quits.
  146.     */
  147.     
  148. void CloseSpriteMgr(void)
  149. {
  150.     CTabHandle cTable;
  151.     GDHandle device;
  152.     short err;
  153.     
  154.     VRemove((QElemPtr) &Sprite_Mgr_Globals->task.qLink);
  155.     device = Sprite_Mgr_Globals->deviceUsed;
  156.     if (Sprite_Mgr_Globals->originalCTable) {
  157.         cTable = (**(**device).gdPMap).pmTable;
  158.         (**(**device).gdPMap).pmTable = Sprite_Mgr_Globals->originalCTable;
  159.         GDeviceChanged(device);
  160.         DisposHandle((Handle) cTable);
  161.     }
  162.     err = SetDepth(device, Sprite_Mgr_Globals->originalDepth, 1, 1);
  163.     
  164.     while (Sprite_Mgr_Globals->backSprites)
  165.         KillSprite(Sprite_Mgr_Globals->backSprites->id);
  166.     while (Sprite_Mgr_Globals->normSprites)
  167.         KillSprite(Sprite_Mgr_Globals->normSprites->id);
  168.     while (Sprite_Mgr_Globals->foreSprites)
  169.         KillSprite(Sprite_Mgr_Globals->foreSprites->id);
  170.  
  171.     while (Sprite_Mgr_Globals->backgrounds)
  172.         KillBackground(Sprite_Mgr_Globals->backgrounds->id);
  173.     while (Sprite_Mgr_Globals->foregrounds)
  174.         KillForeground(Sprite_Mgr_Globals->foregrounds->id);
  175.     
  176.     if (Sprite_Mgr_Globals->animationWindow)
  177.         DisposeWindow((WindowPtr) Sprite_Mgr_Globals->animationWindow);
  178.     if (Sprite_Mgr_Globals->animationGWorld)
  179.         DisposeGWorld(Sprite_Mgr_Globals->animationGWorld);
  180.     if (Sprite_Mgr_Globals->currCTable)
  181.         DisposHandle((Handle) Sprite_Mgr_Globals->currCTable);
  182.     DisposPtr((Ptr) Sprite_Mgr_Globals);
  183.     Sprite_Mgr_Globals = 0L;
  184. }
  185.  
  186.  
  187.     
  188.     
  189.     
  190.     
  191.     /*
  192.         This routine creates a new background by creating a new graphics world and drawing
  193.         in it the picture with id pictID.  drawOrder is the background drawing priority 
  194.         with 1 being the highest priority.  The highest priority gets drawn first.  copyMode
  195.         should be srcCopy for the highest priority element and transparent for the rest.
  196.         animationRect is the area within the animation screen where the background will be
  197.         drawn.  The size of the picture must be at least as big as the animationRect and can
  198.         be bigger if the area is to be scrolled later in the animation.  If the given pictID
  199.         is already in use by another graphic entity then graphics world will be shared instead
  200.         of creating a new graphics world.
  201.         id is returned if no errors occur.  Otherwise 0 if there was not enough memory for the
  202.         offscreen world or the picture could not be loaded.
  203.     */
  204.     
  205.     
  206.     
  207. short NewBackground(short pictID, short drawOrder, short copyMode, Rect *animationRect, short id)
  208. {
  209.     return (NewScenery(pictID, drawOrder, copyMode, animationRect, id, true));
  210. }
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.                     
  219.  
  220.  
  221.     /*
  222.         This routine creates a new foreground by creating a new graphics world and drawing
  223.         in it the picture with id pictID.  drawOrder is the foreground drawing priority 
  224.         with 1 being the highest priority.  The highest priority gets drawn first.  copyMode
  225.         should be transparent in most cases.
  226.         animationRect is the area within the animation screen where the foreground will be
  227.         drawn.  The size of the picture must be at least as big as the animationRect and can
  228.         be bigger if the area is to be scrolled later in the animation.  If the given pictID
  229.         is already in use by another graphic entity then graphics world will be shared instead
  230.         of creating a new graphics world.
  231.         id is returned if no errors occur.  Otherwise 0 if there was not enough memory for the
  232.         offscreen world or the picture could not be loaded.
  233.     */
  234.     
  235.  
  236.  
  237. short NewForeground(short pictID, short drawOrder, short copyMode, Rect *animationRect, short id)
  238. {
  239.     return (NewScenery(pictID, drawOrder, copyMode, animationRect, id, true));
  240. }
  241.                     
  242.  
  243.     
  244.  
  245.  
  246.     /*
  247.         This routine changes the offsets where the image is to be drawn in the animation
  248.         world and marks the background as changed so that is it redrawn again.
  249.     */
  250.  
  251.  
  252.  
  253. void ScrollBackground(short id, short vOffset, short hOffset)
  254. {
  255.     SceneryInfoRecPtr sc;
  256.     
  257.     sc = Sprite_Mgr_Globals->backgrounds;
  258.     while (sc) {
  259.         if (sc->id == id) {
  260.             sc->scrollOffset.v += vOffset;
  261.             sc->scrollOffset.h += hOffset;
  262.             sc->changed = true;
  263.             return;
  264.         }
  265.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  266.     }
  267. }
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.     /*
  278.         This routine changes the offsets where the image is to be drawn in the animation
  279.         world and marks the foreground as changed so that is it redrawn again.
  280.     */
  281.  
  282.  
  283. void ScrollForeground(short id, short vOffset, short hOffset)
  284. {
  285.     SceneryInfoRecPtr sc;
  286.     
  287.     sc = Sprite_Mgr_Globals->foregrounds;
  288.     while (sc) {
  289.         if (sc->id == id) {
  290.             sc->scrollOffset.v += vOffset;
  291.             sc->scrollOffset.h += hOffset;
  292.             sc->changed = true;
  293.             return;
  294.         }
  295.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  296.     }
  297. }
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.     /*
  310.         This routine sets an auto scroll timer and amount for a background to
  311.         be scrolled automatically.  Autoscrolling has some limitations at the
  312.         time.
  313.     */
  314.  
  315. void AutoScrollBackground(short id, short vOffset, short hOffset, long scrollTicks)
  316. {
  317.     SceneryInfoRecPtr sc;
  318.     
  319.     sc = Sprite_Mgr_Globals->backgrounds;
  320.     while (sc) {
  321.         if (sc->id == id) {
  322.             sc->nextTickCount = TickCount() + scrollTicks;
  323.             sc->scrollTicks = scrollTicks;
  324.             sc->autoScrollAmount.v = vOffset;
  325.             sc->autoScrollAmount.h = hOffset;
  326.             return;
  327.         }
  328.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  329.     }
  330. }
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.     /*
  341.         This routine sets an auto scroll timer and amount for a foreground to
  342.         be scrolled automatically.  Autoscrolling has some limitations at the
  343.         time.
  344.     */
  345.  
  346. void AutoScrollForeground(short id, short vOffset, short hOffset, long scrollTicks)
  347. {
  348.     SceneryInfoRecPtr sc;
  349.     
  350.     sc = Sprite_Mgr_Globals->foregrounds;
  351.     while (sc) {
  352.         if (sc->id == id) {
  353.             sc->nextTickCount = TickCount() + scrollTicks;
  354.             sc->scrollTicks = scrollTicks;
  355.             sc->autoScrollAmount.v = vOffset;
  356.             sc->autoScrollAmount.h = hOffset;
  357.             return;
  358.         }
  359.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  360.     }
  361. }
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.     /*
  374.         This routine disposes of the graphics world used by the graphic entity with
  375.         id number id if the graphics world is not being shared by other graphic entities.
  376.         It also deletes any information about this entity from the Sprite Manager
  377.         animation record.
  378.     */
  379.  
  380.  
  381.  
  382. void KillBackground(short id)
  383. {
  384.     SceneryInfoRecPtr sc, sc2;
  385.     
  386.     sc = Sprite_Mgr_Globals->backgrounds;
  387.     if (sc && (sc->id == id)) {
  388.         Sprite_Mgr_Globals->backgrounds = (SceneryInfoRecPtr)
  389.                     sc->nextScenery;
  390.         if (sc->shared) {
  391.             sc2 = FindTwinScenery(sc->pictID);
  392.             if (sc2)
  393.                 sc->sceneryWorld = 0L;
  394.         }
  395.         if (sc->sceneryWorld)
  396.             DisposeGWorld(sc->sceneryWorld);
  397.         DisposPtr((Ptr) sc);
  398.         return;
  399.     }
  400.     sc2 = sc;
  401.     sc = (SceneryInfoRecPtr) sc2->nextScenery;
  402.     while (sc) {
  403.         if (sc->id == id) {
  404.             sc2->nextScenery = sc->nextScenery;
  405.             if (sc->shared) {
  406.                 sc2 = FindTwinScenery(sc->pictID);
  407.                 if (sc2)
  408.                     sc->sceneryWorld = 0L;
  409.             }
  410.             if (sc->sceneryWorld)
  411.                 DisposeGWorld(sc->sceneryWorld);
  412.             DisposPtr((Ptr) sc);
  413.             return;
  414.         }
  415.         sc2 = sc;
  416.         if (sc)
  417.             sc = (SceneryInfoRecPtr) sc->nextScenery;
  418.     }
  419. }
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.     /*
  432.         This routine disposes of the graphics world used by the graphic entity with
  433.         id number id if the graphics world is not being shared by other graphic entities.
  434.         It also deletes any information about this entity from the Sprite Manager
  435.         animation record.
  436.     */
  437.  
  438.  
  439. void KillForeground(short id)
  440. {
  441.     SceneryInfoRecPtr sc, sc2;
  442.     
  443.     sc = Sprite_Mgr_Globals->foregrounds;
  444.     if (sc && (sc->id == id)) {
  445.         Sprite_Mgr_Globals->foregrounds = (SceneryInfoRecPtr)
  446.                 sc->nextScenery;
  447.         if (sc->shared) {
  448.             sc2 = FindTwinScenery(sc->pictID);
  449.             if (sc2)
  450.                 sc->sceneryWorld = 0L;
  451.         }
  452.         if (sc->sceneryWorld)
  453.             DisposeGWorld(sc->sceneryWorld);
  454.         DisposPtr((Ptr) sc);
  455.         return;
  456.     }
  457.     sc2 = sc;
  458.     sc = (SceneryInfoRecPtr) sc2->nextScenery;
  459.     while (sc) {
  460.         if (sc->id == id) {
  461.             sc2->nextScenery = sc->nextScenery;
  462.             if (sc->shared) {
  463.                 sc2 = FindTwinScenery(sc->pictID);
  464.                 if (sc2)
  465.                     sc->sceneryWorld = 0L;
  466.             }
  467.             if (sc->sceneryWorld)
  468.                 DisposeGWorld(sc->sceneryWorld);
  469.             DisposPtr((Ptr) sc);
  470.             return;
  471.         }
  472.         sc2 = sc;
  473.         if (sc)
  474.             sc = (SceneryInfoRecPtr) sc->nextScenery;
  475.     }
  476. }
  477.  
  478.     
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.     /*
  493.         This routine creates a graphics world for the new sprite.  If the same pictID is
  494.         shared by another sprite then the graphics world will be shared between all the
  495.         sprites that share the same picture.  Otherwise the picture range from pictID to
  496.         pictID + totalPicts will be drawn in the new graphics world.  copyMode should be
  497.         transparent in most cases but could be blend in some cases.  spriteProc is a
  498.         procedure pointer that if given can be called every ProcTicks ticks
  499.         (sixthieths of a second).  If ProcTicks is not zero and spriteProc is nil then
  500.         the Sprite Manager will automatically change the current face of the sprite 
  501.         every ProcTicks ticks to the next face.  drawOrder is the priority in which the
  502.         sprite will be drawn with 1 being the highest priority.  collisionProc is a procedure
  503.         pointer that will be called when a collision with another sprite is detected only if
  504.         the parameter canColide is set to true and the collision occurs with another sprite.
  505.         id is the id number that will be used to identify this sprite.
  506.         
  507.         
  508.         Parameters to the collisionProc are the id of the sprite that collided with this
  509.         sprite.
  510.         
  511.         pascal void CollisionProc(short spriteID);
  512.         
  513.         Parameters to the sprite procedure are the id of the sprite and the rectangle which
  514.         encloses the sprite in the animation world.
  515.         
  516.         pascal void SpriteProc(short spriteID, Rect *locationRect);
  517.     */
  518.  
  519.  
  520. short NewBackgroundSprite(short pictID, short totalPicts, short copyMode,
  521.                         ProcPtr spriteProc, long ProcTicks, short drawOrder,
  522.                         ProcPtr collisionProc, Boolean canColide, short id)
  523. {
  524.     return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder,
  525.             collisionProc, canColide, id, 1));
  526. }
  527.     
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.     /*
  546.         This routine creates a graphics world for the new sprite.  If the same pictID is
  547.         shared by another sprite then the graphics world will be shared between all the
  548.         sprites that share the same picture.  Otherwise the picture range from pictID to
  549.         pictID + totalPicts will be drawn in the new graphics world.  copyMode should be
  550.         transparent in most cases but could be blend in some cases.  spriteProc is a
  551.         procedure pointer that if given can be called every ProcTicks ticks
  552.         (sixthieths of a second).  If ProcTicks is not zero and spriteProc is nil then
  553.         the Sprite Manager will automatically change the current face of the sprite 
  554.         every ProcTicks ticks to the next face.  drawOrder is the priority in which the
  555.         sprite will be drawn with 1 being the highest priority.  collisionProc is a procedure
  556.         pointer that will be called when a collision with another sprite is detected only if
  557.         the parameter canColide is set to true and the collision occurs with another sprite.
  558.         id is the id number that will be used to identify this sprite.
  559.         
  560.         
  561.         Parameters to the collisionProc are the id of the sprite that collided with this
  562.         sprite.
  563.         
  564.         pascal void CollisionProc(short spriteID);
  565.         
  566.         Parameters to the sprite procedure are the id of the sprite and the rectangle which
  567.         encloses the sprite in the animation world.
  568.         
  569.         pascal void SpriteProc(short spriteID, Rect *locationRect);
  570.     */
  571.     
  572.  
  573. short NewSprite(short pictID, short totalPicts, short copyMode,
  574.                         ProcPtr spriteProc, long ProcTicks, short drawOrder,
  575.                         ProcPtr collisionProc, Boolean canColide, short id)
  576. {
  577.     return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder,
  578.             collisionProc, canColide, id, 2));
  579. }
  580.     
  581.     
  582.     
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.     /*
  598.         This routine creates a graphics world for the new sprite.  If the same pictID is
  599.         shared by another sprite then the graphics world will be shared between all the
  600.         sprites that share the same picture.  Otherwise the picture range from pictID to
  601.         pictID + totalPicts will be drawn in the new graphics world.  copyMode should be
  602.         transparent in most cases but could be blend in some cases.  spriteProc is a
  603.         procedure pointer that if given can be called every ProcTicks ticks
  604.         (sixthieths of a second).  If ProcTicks is not zero and spriteProc is nil then
  605.         the Sprite Manager will automatically change the current face of the sprite 
  606.         every ProcTicks ticks to the next face.  drawOrder is the priority in which the
  607.         sprite will be drawn with 1 being the highest priority.  collisionProc is a procedure
  608.         pointer that will be called when a collision with another sprite is detected only if
  609.         the parameter canColide is set to true and the collision occurs with another sprite.
  610.         id is the id number that will be used to identify this sprite.
  611.         
  612.         
  613.         Parameters to the collisionProc are the id of the sprite that collided with this
  614.         sprite.
  615.         
  616.         pascal void CollisionProc(short spriteID);
  617.         
  618.         Parameters to the sprite procedure are the id of the sprite and the rectangle which
  619.         encloses the sprite in the animation world.
  620.         
  621.         pascal void SpriteProc(short spriteID, Rect *locationRect);
  622.     */
  623.  
  624. short NewForegroundSprite(short pictID, short totalPicts, short copyMode,
  625.                         ProcPtr spriteProc, long ProcTicks, short drawOrder,
  626.                         ProcPtr collisionProc, Boolean canColide, short id)
  627. {
  628.     return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder,
  629.             collisionProc, canColide, id, 3));
  630. }
  631.     
  632.     
  633.     
  634.     
  635.     
  636.     
  637.     
  638.     
  639.     
  640.     
  641.  
  642.  
  643.     /*
  644.         This procedure creates a new animation world and creates a graphics world
  645.         for it.  animationRect is the rectangle which will be used for the animation
  646.         in a window to be created by this procedure.  The window will be created in the
  647.         graphics device which supports 4 bit color.  windowH is the width of the window
  648.         to be created and windowV is the height of the window.  wTitle is the title that
  649.         will be given to the window.  The window created will be centered in the graphics
  650.         device.  A color window pointer is returned to the caller so that the application
  651.         can use the areas outside the animationRect for purposes other than animation such
  652.         as scores.
  653.     */
  654.  
  655.  
  656.  
  657.  
  658. CWindowPtr NewAnimation(Rect *animationRect, short windowH, short windowV, Str255 wTitle)
  659. {
  660.     Rect box;
  661.     short err;
  662.     GWorldPtr world = 0L;
  663.     CTabHandle cTable;
  664.     short offsetV, offsetH;
  665.     CGrafPtr savedGWorld;
  666.     GDHandle savedGD;
  667.     
  668.     GetGWorld(&savedGWorld, &savedGD);
  669.     box = (**(Sprite_Mgr_Globals->deviceUsed)).gdRect;
  670.     offsetV = box.bottom - box.top - windowV;
  671.     offsetH = box.right - box.left - windowH;
  672.     if (offsetV > 0)
  673.         offsetV /= 2;
  674.     else
  675.         offsetV = 0;
  676.     if (offsetH > 0)
  677.         offsetH /= 2;
  678.     else
  679.         offsetH = 0;
  680.     box.right = box.left + windowH + offsetH;
  681.     box.bottom = box.top + windowV + offsetV;
  682.     box.top += offsetV;
  683.     box.left += offsetH;
  684.     Sprite_Mgr_Globals->animationWindow = (CWindowPtr) NewCWindow(0L, &box, wTitle,
  685.                 true, documentProc, (WindowPtr) -1L, false, 'Anim');
  686.     Sprite_Mgr_Globals->animationRect = *animationRect;
  687.     cTable = Sprite_Mgr_Globals->currCTable;
  688.     err = NewGWorld(&world, desiredPixSize, animationRect, cTable, 0L, (long) useTempMem);
  689.     if (!err) {
  690.         SetGWorld(world, 0L);
  691.         EraseRect(animationRect);
  692.     }
  693.     Sprite_Mgr_Globals->animationGWorld = world;
  694.     if (!world) {
  695.         DisposeWindow((WindowPtr) Sprite_Mgr_Globals->animationWindow);
  696.         Sprite_Mgr_Globals->animationWindow = 0L;
  697.     }
  698.     SetGWorld(savedGWorld, savedGD);
  699.     return(Sprite_Mgr_Globals->animationWindow);
  700. }
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.     
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720.     /*
  721.         This procedure set the current face of the sprite with id number id to the
  722.         given index.  The changed flag is set to true so that drawing is performed in
  723.         the next chance by the Sprite Manager.
  724.     */
  725.  
  726.  
  727.  
  728. void SetCurrentSpriteIndex(short id, short index)
  729. {
  730.     SpriteInfoRecPtr p;
  731.     
  732.     p = FindSprite(id);
  733.     if (p) {
  734.         p->changed = true;
  735.         p->currentFace = index;
  736.     }
  737. }
  738.  
  739.     
  740.     
  741.     
  742.     
  743.     
  744.     
  745.     
  746.     
  747.     
  748.     
  749.     
  750.     
  751.     
  752.     /*
  753.         This procedure puts the sprite in the animation world at the location given
  754.         by top and left.  The changed flag is set to true so that drawing is performed
  755.         as soon as possible.  A sprite should only be "put" in the animation world
  756.         once unless it is first "removed" by calling RemoveSprite.
  757.     */
  758.     
  759. void PutSprite(short id, short top, short left)
  760. {
  761.     SpriteInfoRecPtr p;
  762.     
  763.     p = FindSprite(id);
  764.     if (p) {
  765.         p->changed = true;
  766.         p->animationRect = p->spriteRect;
  767.         p->animationRect.top += top;
  768.         p->animationRect.bottom += top;
  769.         p->animationRect.left += left;
  770.         p->animationRect.right += left;
  771.     }
  772. }
  773.  
  774.  
  775.     
  776.     
  777.     
  778.     
  779.  
  780.  
  781.  
  782.  
  783.  
  784.  
  785.  
  786.  
  787.     /*
  788.         This procedure removes a sprite from the animation world by setting its
  789.         animation rectangle to an empty rectangle and setting the sprite's changed
  790.         flag so that the animation world is updated correctly.
  791.     */
  792.     
  793. void RemoveSprite(short id)
  794. {
  795.     SpriteInfoRecPtr p;
  796.     
  797.     p = FindSprite(id);
  798.     if (p) {
  799.         p->changed = true;
  800.         p->animationRect.top = p->animationRect.left =
  801.                     p->animationRect.bottom = p->animationRect.right = 0;
  802.     }
  803. }
  804.  
  805.     
  806.     
  807.     
  808.     
  809.     
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.     /*
  823.         This procedure moves the sprite in the animation world first remembering the
  824.         sprite's old location for further updating.  The sprite's location is offset by
  825.         h and v.  A new face for the sprite can be given by newIndex if newIndex is not
  826.         zero.  Once a sprite is "put" in the animation world it should
  827.     */
  828.     
  829.     
  830. void MoveSprite(short id, short h, short v, short newIndex)
  831. {
  832.     SpriteInfoRecPtr p;
  833.     
  834.     p = FindSprite(id);
  835.     if (p) {
  836.         p->changed = true;
  837.         p->oldAnimationRect = p->animationRect;
  838.         p->animationRect.top += v;
  839.         p->animationRect.left += h;
  840.         p->animationRect.bottom += v;
  841.         p->animationRect.right += h;
  842.         if (newIndex)
  843.             p->currentFace = newIndex;
  844.     }
  845. }
  846.  
  847.     
  848.     
  849.     
  850.     
  851.     
  852.     
  853.     
  854.     
  855.     
  856.     
  857.     
  858.     
  859.     
  860.     /*
  861.         This procedure moves a sprite with the given id to the location specified by h
  862.         and v.  A new face for thr sprite may be given by specifying a newIndex other
  863.         than zero.  The old location of the sprite is recorded for further updating.
  864.     */
  865.     
  866.  
  867.  
  868. void MoveSpriteTo(short id, short h, short v, short newIndex)
  869. {
  870.     SpriteInfoRecPtr p;
  871.     
  872.     p = FindSprite(id);
  873.     if (p) {
  874.         p->changed = true;
  875.         p->oldAnimationRect = p->animationRect;
  876.         p->animationRect = p->spriteRect;
  877.         p->animationRect.top += v;
  878.         p->animationRect.left += h;
  879.         p->animationRect.bottom += v;
  880.         p->animationRect.right += h;
  881.         if (newIndex)
  882.             p->currentFace = newIndex;
  883.     }
  884. }
  885.  
  886.  
  887.         
  888.  
  889.  
  890.  
  891.  
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.     /*
  901.         This procedure makes visible or invisible a sprite based on the show parameter.
  902.         A "hiden" sprite is not drawn in the animation world but can still create
  903.         collisions if its collision attribute is enabled.  If the new visibility state
  904.         of the sprite is changed the "changed" attribute gets set to true so that the
  905.         animation world is updated correctly.
  906.     */
  907.     
  908.     
  909.     
  910. void ShowSprite(short id, Boolean show)
  911. {
  912.     SpriteInfoRecPtr p;
  913.     
  914.     p = FindSprite(id);
  915.     if (p) {
  916.         if (show != p->hidden) {
  917.             p->changed = true;
  918.             p->oldAnimationRect = p->animationRect;
  919.             p->hidden = show;
  920.         }
  921.     }
  922. }
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.     
  935.     
  936.     
  937.     
  938.     
  939.     
  940.     /*
  941.         This procedure returns the current location of the given sprite in the animation
  942.         world or an empty rectangle if the sprite is not currently in the animation world.
  943.         More detailed information can be obtained by calling GetSpriteInfo.
  944.     */
  945.  
  946.     
  947.     
  948. void GetSpriteLocation(short id, Rect *location)
  949. {
  950.     SpriteInfoRecPtr p;
  951.     
  952.     p = FindSprite(id);
  953.     if (p) {
  954.         *location = p->animationRect;
  955.     }
  956.     else {
  957.         SetRect(location, 0, 0, 0, 0);
  958.     }
  959. }
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.     /*
  973.         This procedure enables or disables collisions for a sprite based on the enable value.
  974.         Sprites with collisions enabled can only collide with other sprites which
  975.         have the collision attribute set to true.
  976.     */
  977.     
  978.  
  979.  
  980. void EnableSpriteCollisions(short id, Boolean enable)
  981. {
  982.     SpriteInfoRecPtr p;
  983.     
  984.     p = FindSprite(id);
  985.     if (p) {
  986.         p->canCollide = enable;
  987.     }
  988. }
  989.  
  990.     
  991.     
  992.     
  993.     
  994.     
  995.     
  996.     
  997.     
  998.     
  999.     
  1000.     
  1001.  
  1002.     /*
  1003.         This is a special purpose call which "validates" the old rectangle which ussed to
  1004.         be occupied by a sprite.  Its purpose is to prevent redundant drawing from occuring
  1005.         when an specific sprite and face moves into the position previously occupied by
  1006.         an identical sprite and face.
  1007.     */
  1008.     
  1009.     
  1010. void ValidateOldSpriteLocation(short id)
  1011. {
  1012.     SpriteInfoRecPtr p;
  1013.     
  1014.     p = FindSprite(id);
  1015.     if (p) {
  1016.         p->oldAnimationRect.top = p->oldAnimationRect.left = p->oldAnimationRect.bottom =
  1017.                 p->oldAnimationRect.right = 0;
  1018.     }
  1019. }
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.     
  1027.     
  1028.     
  1029.     
  1030.     
  1031.  
  1032.  
  1033.  
  1034.  
  1035.     /*
  1036.         This call allows the programmer to specify a collision area for a sprite other than
  1037.         the sprite's own dimensions.  The collision rectangle is given in the sprite's
  1038.         local coordinate system.  By using this call collisions can be limited to a certain
  1039.         portion of th sprite's area.
  1040.     */
  1041.     
  1042.     
  1043.     
  1044. void SetSpriteCollisionRect(short id, Rect *colRect)
  1045. {
  1046.     SpriteInfoRecPtr p;
  1047.     
  1048.     p = FindSprite(id);
  1049.     if (p) {
  1050.         p->collisionRect = *colRect;
  1051.     }
  1052. }
  1053.  
  1054.  
  1055.  
  1056.     
  1057.     
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068.  
  1069.  
  1070.     /*
  1071.         This function returns a pointer to a sprite information record.  The pointer returned
  1072.         is valid for the life of the sprite.  That is until is the sprite is "killed" with
  1073.         a call to "KillSprite".  The data structure returned by this call should be used mostly
  1074.         for read-only purposes.  Altering values in the data structure could result in
  1075.         animation errors.
  1076.     */
  1077.     
  1078.     
  1079.     
  1080. SpriteInfoRecPtr GetSpriteInfo(short id)
  1081. {
  1082.     SpriteInfoRecPtr p;
  1083.     
  1084.     p = FindSprite(id);
  1085.     if (p)
  1086.         return(p);
  1087.     return(0L);
  1088. }
  1089.     
  1090.     
  1091.     
  1092.     
  1093.     
  1094.     
  1095.  
  1096.  
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104.  
  1105.     /*
  1106.         This procedure destroys the graphics world used by the sprite with the given id
  1107.         if such sprite is not currently sharing a graphics world with another sprite.
  1108.         If the sprite is currently in the animaton screen its area is recorded so it
  1109.         can be updated as soon as possible by the Sprite Manager.
  1110.     */
  1111.  
  1112.     
  1113.     
  1114. void KillSprite(short id)
  1115. {
  1116.     SpriteInfoRecPtr p, p2, twin1, twin2;
  1117.     register short counter;
  1118.     
  1119.     for (counter = 0; counter < 3; counter++) {
  1120.         if (counter == 0)
  1121.             p = Sprite_Mgr_Globals->normSprites;
  1122.         if (counter == 1)
  1123.             p = Sprite_Mgr_Globals->backSprites;
  1124.         if (counter == 2)
  1125.             p = Sprite_Mgr_Globals->foreSprites;
  1126.         if (p) {
  1127.             if (p->id == id) {
  1128.                 if (counter == 0)
  1129.                     Sprite_Mgr_Globals->normSprites = (SpriteInfoRecPtr) p->nextSprite;
  1130.                 if (counter == 1)
  1131.                     Sprite_Mgr_Globals->backSprites = (SpriteInfoRecPtr) p->nextSprite;
  1132.                 if (counter == 2)
  1133.                     Sprite_Mgr_Globals->foreSprites = (SpriteInfoRecPtr) p->nextSprite;
  1134.                 if (p->sharedWorld) {
  1135.                     p->sharedWorld = false;                    // mark as unshared so FindTwin wont give us ourselves
  1136.                     twin1 = FindTwinSprite(p->pictID);        // find a twin
  1137.                     if (!twin1)
  1138.                         DisposeGWorld(p->spriteWorld);        // no twins ! weird..
  1139.                     else {
  1140.                         twin1->sharedWorld = false;            // disable this one temporarily
  1141.                         twin2 = FindTwinSprite(p->pictID);    // are there any more ?
  1142.                         if (twin2)
  1143.                             twin1->sharedWorld = true;        // restore shared status since there are more sharing
  1144.                     }
  1145.                 }
  1146.                 else {
  1147.                     DisposeGWorld(p->spriteWorld);
  1148.                 }
  1149.                 DisposPtr((Ptr) p);
  1150.                 return;
  1151.             }
  1152.             p2 = p;
  1153.             p = (SpriteInfoRecPtr) p->nextSprite;
  1154.             while (p) {
  1155.                 if (p->id == id) {
  1156.                     if (p->sharedWorld) {
  1157.                         p->sharedWorld = false;                    // mark as unshared so FindTwin wont give us ourselves
  1158.                         twin1 = FindTwinSprite(p->pictID);        // find a twin
  1159.                         if (!twin1)
  1160.                             DisposeGWorld(p->spriteWorld);        // no twins ! weird..
  1161.                         else {
  1162.                             twin1->sharedWorld = false;            // disable this one temporarily
  1163.                             twin2 = FindTwinSprite(p->pictID);    // are there any more ?
  1164.                             if (twin2)
  1165.                                 twin1->sharedWorld = true;        // restore shared status since there are more sharing
  1166.                         }
  1167.                     }
  1168.                     else {
  1169.                         DisposeGWorld(p->spriteWorld);
  1170.                     }
  1171.                     p2->nextSprite = p->nextSprite;
  1172.                     DisposPtr((Ptr) p);
  1173.                     return;
  1174.                 }
  1175.                 p2 = p;
  1176.                 p = (SpriteInfoRecPtr) p->nextSprite;
  1177.             }
  1178.         }
  1179.     }
  1180. }
  1181.  
  1182.     
  1183.     
  1184.     
  1185.     
  1186.     
  1187.     
  1188.     
  1189.     
  1190.     
  1191.     
  1192.     
  1193.     
  1194.     
  1195.     
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.     /*
  1205.         This routine activates the animation world so that animation will occur the next
  1206.         time DoAnimation is called.  The deafult state after calling NewAnimation is to have
  1207.         the animation world inactive.  All applications other than the current one are hidden
  1208.         so that the processing time is dedicated to the animation application.
  1209.     */
  1210.         
  1211.     
  1212.     
  1213. void ActivateAnimation(void)
  1214. {
  1215.     Sprite_Mgr_Globals->active = true;
  1216. }
  1217.  
  1218.     
  1219.     
  1220.     
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.     /*
  1230.         This routine prevents any animation from ocurring by deactivating the animation
  1231.         world.  This is the deafult state after calling NewAnimation.  This procedure should
  1232.         be called when the animation is to be suspended.  It also enabled all other applications
  1233.         so that the user can swith applications.
  1234.     */
  1235.     
  1236.     
  1237. void DeactivateAnimation(void)
  1238. {
  1239.     Sprite_Mgr_Globals->active = true;
  1240. }
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.  
  1249.  
  1250.  
  1251.  
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.     /*
  1258.         This is the main driver for the animation.  If the parameter update is set to
  1259.         true then the animation world is simply redrawn.  Call DoAnimation with update
  1260.         set to true when you receive an update event.  When an update event occurs the
  1261.         application must bracket this call with BeginUpdate and EndUpdate and any
  1262.         application specific drawing ouside the animation area must be redrawn as well.
  1263.         When update is set to false this procedure animates the animation world by doing
  1264.         several things.
  1265.         
  1266.             1) Go trough the backgrounds updating the animation area as nessesary.
  1267.             2) Detect sprite collisions and calling collision procedures if nessesary.
  1268.             3) Check the tick counters and calling the tickle procedures if any.
  1269.             4) Updating automatic tickling sprites.
  1270.             5) Drawing any sprites that have changed their face.
  1271.             6) Updating foregounds.
  1272.             7) Updating foreground sprites that have changed.
  1273.     */
  1274.  
  1275.  
  1276. void DoAnimation(Boolean update)
  1277. {
  1278.     GrafPtr g1, g2;
  1279.     Rect sRect;
  1280.     register short counter, total;
  1281.     register Rect *boxPtr;
  1282.     KeyMap keys;
  1283.     
  1284.     if (update) {
  1285.         g1 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld;
  1286.         g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow;
  1287.         sRect = Sprite_Mgr_Globals->animationRect;
  1288.         Sprite_Mgr_Globals->task.inVBL = 0;
  1289.         while (Sprite_Mgr_Globals->task.inVBL == 0)
  1290.             ;
  1291.         CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &sRect, srcCopy, 0L);
  1292.         return;
  1293.     }
  1294.     if (Sprite_Mgr_Globals->active == false)
  1295.         return;
  1296.     Sprite_Mgr_Globals->changed = false;
  1297.     
  1298.     // next: update only changed rectangles on sceneries
  1299.     // Detect collisions
  1300.     
  1301.     
  1302.     do {
  1303.         Sprite_Mgr_Globals->redoCheck = false;
  1304.         CheckChangedScenery(Sprite_Mgr_Globals->backgrounds);    // backgrounds
  1305.         CheckChangedSprite(Sprite_Mgr_Globals->backSprites);    // back sprites
  1306.         CheckChangedSprite(Sprite_Mgr_Globals->normSprites);    // sprites
  1307.         CheckChangedScenery(Sprite_Mgr_Globals->foregrounds);    // foregrounds
  1308.         CheckChangedSprite(Sprite_Mgr_Globals->foreSprites);    // fore sprites
  1309.     } while (Sprite_Mgr_Globals->redoCheck);
  1310.     
  1311.     Sprite_Mgr_Globals->updateRects = 0;    // nothing to update
  1312.     
  1313.     UpdateScenery(Sprite_Mgr_Globals->backgrounds);    // changed backgrounds
  1314.     UpdateSprite(Sprite_Mgr_Globals->backSprites);
  1315.     UpdateSprite(Sprite_Mgr_Globals->normSprites);        // changed sprites
  1316.     UpdateScenery(Sprite_Mgr_Globals->foregrounds);    // changed foregrounds
  1317.     UpdateSprite(Sprite_Mgr_Globals->foreSprites);
  1318.     
  1319.     if (Sprite_Mgr_Globals->changed == false)
  1320.         return;
  1321.     g1 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld;
  1322.     g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow;
  1323.     
  1324.     GetKeys(&keys[0]);
  1325.     if ((keys[1] & 0x4) == 0)
  1326.         Sprite_Mgr_Globals->updateRects = kMaxUR;
  1327.     if (Sprite_Mgr_Globals->updateRects == kMaxUR) {    // update full screen
  1328.         sRect = Sprite_Mgr_Globals->animationRect;
  1329.         Sprite_Mgr_Globals->task.inVBL = 0;
  1330.         while (Sprite_Mgr_Globals->task.inVBL == 0)
  1331.             ;
  1332.         CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &sRect, srcCopy, 0L);
  1333.     }
  1334.     else {
  1335.         total = Sprite_Mgr_Globals->updateRects;
  1336.         boxPtr = &(Sprite_Mgr_Globals->changedRect[0]);
  1337.         for (counter = 0; counter < total; counter++) {
  1338.             Sprite_Mgr_Globals->task.inVBL = 0;
  1339.             while (Sprite_Mgr_Globals->task.inVBL == 0)
  1340.                 ;
  1341.             CopyBits(&(g1->portBits), &(g2->portBits), boxPtr, boxPtr, srcCopy, 0L);
  1342.             boxPtr++;
  1343.         }
  1344.         Sprite_Mgr_Globals->updateRects = 0;
  1345.     }
  1346. }
  1347.  
  1348.     
  1349.  
  1350.  
  1351.  
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365.  
  1366.     /*
  1367.         This procedure changes the current animation pallete used in the animation world
  1368.         to the new color table.
  1369.     */
  1370.  
  1371.  
  1372.  
  1373. void SetNewAnimationPallete(CTabHandle cTable)
  1374. {
  1375.     GDHandle dev;
  1376.     
  1377.     dev = Sprite_Mgr_Globals->deviceUsed;
  1378.     cTable = (**(**dev).gdPMap).pmTable;
  1379.     (**(**dev).gdPMap).pmTable = cTable;
  1380.     DisposHandle((Handle) cTable);
  1381.     GDeviceChanged(dev);
  1382. }
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393. /************************************************************************************
  1394.  
  1395.     P R I V A T E       R O U T I N E S
  1396.     
  1397. *************************************************************************************/
  1398.  
  1399.  
  1400.  
  1401.     /*
  1402.         This is the common routine to create sceneries, we use this routine because we want
  1403.         to make things more readable for the programmer by providing "specialized" routines
  1404.         that allow them to distinguish between foregrounds and backgrounds.
  1405.         The basic process is to create the scenery data structure, fill in the default values,
  1406.         create the graphics world, load the picture and copy it into the g world, then
  1407.         the scenery data structure is inserted in the right place.
  1408.         I suppose that later on we could insert them in the linked list in their priority
  1409.         order.
  1410.     */
  1411.  
  1412.  
  1413. short NewScenery(short pictID, short drawOrder, short copyMode, Rect *animationRect,
  1414.                 short id, Boolean back)
  1415. {
  1416.     SceneryInfoRecPtr sc, sc2, sc3;
  1417.     short err;
  1418.     PicHandle picH;
  1419.     Rect box;
  1420.     GWorldPtr world;
  1421.     CGrafPtr CsavePort;
  1422.     GDHandle gd;
  1423.     PixMapHandle pixH;
  1424.     
  1425.     sc = (SceneryInfoRecPtr) NewPtrClear(sizeof(SceneryInfoRec));
  1426.     if (!sc)
  1427.         return(0);
  1428.     sc->id = id;
  1429.     sc->pictID = pictID;
  1430.     sc->drawOrder = drawOrder;
  1431.     sc->copyMode = copyMode;
  1432.     sc->animationRect = *animationRect;
  1433.     sc->hidden = false;
  1434.     sc->changed = true;
  1435.     sc->shared = false;
  1436.     sc2 = FindTwinScenery(pictID);
  1437.     if (sc2) {
  1438.         sc->shared = true;
  1439.         sc2->shared = true;
  1440.         sc->sceneryWorld = sc2->sceneryWorld;
  1441.         sc->sceneryRect = sc2->sceneryRect;
  1442.     }
  1443.     else {
  1444.         picH = GetPicture(pictID);
  1445.         if (!picH) {
  1446.             DisposPtr((Ptr) sc);
  1447.             return(0);
  1448.         }
  1449.         LoadResource((Handle) picH);
  1450.         HLock((Handle) picH);
  1451.         box = (**picH).picFrame;
  1452.         box.right = box.right - box.left;
  1453.         box.bottom = box.bottom - box.top;
  1454.         box.top = box.left = 0;
  1455.         sc->sceneryRect = box;
  1456.         GetGWorld(&CsavePort, &gd);
  1457.         err = NewGWorld( &world, desiredPixSize, &box, 0L, 0L, 0L); // (long) useTempMem);
  1458.         if (err || (world->portPixMap == 0L)) {
  1459.             ReleaseResource((Handle) picH);
  1460.             DisposPtr((Ptr) sc);
  1461.             return(0);
  1462.         }
  1463.         pixH = world->portPixMap;
  1464.         HLock((Handle) pixH);
  1465.         LockPixels(pixH);
  1466.         NoPurgePixels(pixH);
  1467.         SetGWorld(world, 0L);
  1468.         sc->sceneryWorld = world;
  1469.         DrawPicture(picH, &box);
  1470.         ReleaseResource((Handle) picH);
  1471.         SetGWorld(CsavePort, gd);
  1472.     }
  1473.     if (back)
  1474.         sc2 = Sprite_Mgr_Globals->backgrounds;
  1475.     else
  1476.         sc2 = Sprite_Mgr_Globals->foregrounds;
  1477.     if (sc2->id > id) {
  1478.         if (back)
  1479.             Sprite_Mgr_Globals->backgrounds = sc;
  1480.         else
  1481.             Sprite_Mgr_Globals->foregrounds = sc;
  1482.         sc->nextScenery = (Ptr) sc2;
  1483.         return(id);
  1484.     }
  1485.     else {
  1486.         if (back)
  1487.             sc3 = sc2 = Sprite_Mgr_Globals->backgrounds;
  1488.         else
  1489.             sc3 = sc2 = Sprite_Mgr_Globals->foregrounds;
  1490.         while (sc2 && (sc2->id < id)) {
  1491.             sc3 = sc2;
  1492.             sc2 = (SceneryInfoRecPtr) sc2->nextScenery;
  1493.         }
  1494.         if (sc2) {
  1495.             sc3->nextScenery = (Ptr) sc;
  1496.             sc->nextScenery = (Ptr) sc2;
  1497.         }
  1498.         else {
  1499.             sc3->nextScenery = (Ptr) sc;
  1500.         }
  1501.     }
  1502.     return(id);
  1503. }
  1504.     
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.  
  1516.     /*
  1517.         This is the common routine to create sprites, we use this routine because we want
  1518.         to make things more readable for the programmer by providing "specialized" routines
  1519.         that allow them to distinguish between foreground, normal and background sprites.
  1520.         The basic process is to create the sprite data structure, fill in the default values,
  1521.         create the graphics world, load the pictures and copy them into the g world, then
  1522.         the sprite data structure is inserted in the right place.
  1523.         I suppose that later on we could insert them in the linked list in their priority
  1524.         order.
  1525.     */
  1526.  
  1527.  
  1528.  
  1529. short SMgrNewSprite(short pictID, short totalPicts, short copyMode,
  1530.                         ProcPtr spriteProc, long ProcTicks, short drawOrder,
  1531.                         ProcPtr collisionProc, Boolean canCollide, short id, short sType)
  1532. {
  1533.     SpriteInfoRecPtr p, p2, twin;
  1534.     short err, h, v;
  1535.     PicHandle picH;
  1536.     Rect box;
  1537.     GWorldPtr world;
  1538.     CGrafPtr CsavePort;
  1539.     GDHandle gd;
  1540.     PixMapHandle pixH;
  1541.     register short counter;
  1542.     
  1543.     p = (SpriteInfoRecPtr) NewPtrClear(sizeof(SpriteInfoRec));
  1544.     if (!p)
  1545.         return(0);
  1546.     p->id = id;
  1547.     p->pictID = pictID;
  1548.     p->drawOrder = drawOrder;
  1549.     p->copyMode = copyMode;
  1550.     p->oldAnimationRect = p->animationRect;
  1551.     p->tickWait = ProcTicks;
  1552.     p->currentFace = 1;
  1553.     p->sharedWorld = false;
  1554.     p->faces = totalPicts;
  1555.     p->tickProc = spriteProc;
  1556.     p->canCollide = canCollide;
  1557.     p->collisionProc = collisionProc;
  1558.     p->hidden = false;
  1559.     p->changed = true;
  1560.     twin = FindTwinSprite(pictID);
  1561.     if (twin) {
  1562.         twin->sharedWorld = true;
  1563.         p->spriteRect = twin->spriteRect;
  1564.         p->collisionRect = twin->collisionRect;
  1565.         p->spriteWorld = twin->spriteWorld;
  1566.         p->nextSprite = 0L;
  1567.     }
  1568.     else {
  1569.         picH = GetPicture(pictID);
  1570.         if (!picH) {
  1571.             DisposPtr((Ptr) p);
  1572.             return(0);
  1573.         }
  1574.         LoadResource((Handle) picH);
  1575.         HLock((Handle) picH);
  1576.         box = (**picH).picFrame;
  1577.         h = box.right - box.left;
  1578.         v = box.bottom - box.top;
  1579.         box.right = h;        // make zero offset based
  1580.         box.bottom = v;
  1581.         box.top = box.left = 0;
  1582.         p->spriteRect = box;
  1583.         p->collisionRect = box;
  1584.         box.right *= totalPicts;
  1585.         GetGWorld(&CsavePort, &gd);
  1586.         err = NewGWorld( &world, desiredPixSize, &box, 0L, 0L, 0L); // (long) useTempMem);
  1587.         if (err || (world->portPixMap == 0L)) {
  1588.             ReleaseResource((Handle) picH);
  1589.             DisposPtr((Ptr) p);
  1590.             return(0);
  1591.         }
  1592.         pixH = world->portPixMap;
  1593.         HLock((Handle) pixH);
  1594.         LockPixels(pixH);
  1595.         NoPurgePixels(pixH);
  1596.         SetGWorld(world, 0L);
  1597.         EraseRect(&world->portRect);
  1598.         p->spriteWorld = world;
  1599.         p->nextSprite = 0L;
  1600.         for (counter = 0; counter < totalPicts; counter++) {
  1601.             picH = GetPicture(pictID + counter);
  1602.             LoadResource((Handle) picH);
  1603.             HLock((Handle) picH);
  1604.             box = (**picH).picFrame;
  1605.             box.right = box.right - box.left;
  1606.             box.bottom = box.bottom - box.top;
  1607.             box.left = box.top = 0;
  1608.             box.right += h * counter;
  1609.             box.left += h * counter;
  1610.             DrawPicture(picH, &box);
  1611.             ReleaseResource((Handle) picH);
  1612.         }
  1613.         SetGWorld(CsavePort, gd);
  1614.     }
  1615.     if (sType == 1) {
  1616.         p2 = Sprite_Mgr_Globals->backSprites;
  1617.         Sprite_Mgr_Globals->backSprites = p;
  1618.     }
  1619.     if (sType == 2) {
  1620.         p2 = Sprite_Mgr_Globals->normSprites;
  1621.         Sprite_Mgr_Globals->normSprites = p;
  1622.     }
  1623.     if (sType == 3) {
  1624.         p2 = Sprite_Mgr_Globals->foreSprites;
  1625.         Sprite_Mgr_Globals->foreSprites = p;
  1626.     }
  1627.     p->nextSprite = (Ptr) p2;
  1628.     return(id);
  1629. }
  1630.  
  1631.  
  1632.  
  1633.  
  1634.  
  1635.  
  1636.  
  1637.  
  1638.  
  1639.  
  1640.  
  1641.     /*
  1642.         This is a common routine which is used to find a sprite by a given id, this routine
  1643.         gets called by most of the sprite interface routines that allow the programmer to
  1644.         change attributes on a sprite.  The lookup priority is by sprite, then foreground
  1645.         sprite and finally background sprites.  If no sprite is found we return nil.
  1646.     */
  1647.  
  1648. SpriteInfoRecPtr FindSprite(short id)
  1649. {
  1650.     SpriteInfoRecPtr p;
  1651.     
  1652.     p = Sprite_Mgr_Globals->normSprites;
  1653.     while (p) {
  1654.         if (p->id == id)
  1655.             return(p);
  1656.         p = (SpriteInfoRecPtr) p->nextSprite;
  1657.     }
  1658.     p = Sprite_Mgr_Globals->foreSprites;
  1659.     while (p) {
  1660.         if (p->id == id)
  1661.             return(p);
  1662.         p = (SpriteInfoRecPtr) p->nextSprite;
  1663.     }
  1664.     p = Sprite_Mgr_Globals->backSprites;
  1665.     while (p) {
  1666.         if (p->id == id)
  1667.             return(p);
  1668.         p = (SpriteInfoRecPtr) p->nextSprite;
  1669.     }
  1670.     return(0L);
  1671. }
  1672.  
  1673.  
  1674.  
  1675.  
  1676.  
  1677.  
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.     /*
  1684.         This routine is used to find a sprite that needs to share its gworld, since it
  1685.         doesn't make sense to duplicate a gworld which is going to use the same as
  1686.         another one.  This could happen in a "shotter" game for example.
  1687.     */
  1688.  
  1689.  
  1690. SpriteInfoRecPtr FindTwinSprite(short pictID)
  1691. {
  1692.     SpriteInfoRecPtr p;
  1693.     
  1694.     p = Sprite_Mgr_Globals->normSprites;
  1695.     while (p) {
  1696.         if (p->pictID == pictID)
  1697.             return(p);
  1698.         p = (SpriteInfoRecPtr) p->nextSprite;
  1699.     }
  1700.     p = Sprite_Mgr_Globals->foreSprites;
  1701.     while (p) {
  1702.         if (p->pictID == pictID)
  1703.             return(p);
  1704.         p = (SpriteInfoRecPtr) p->nextSprite;
  1705.     }
  1706.     p = Sprite_Mgr_Globals->backSprites;
  1707.     while (p) {
  1708.         if (p->pictID == pictID)
  1709.             return(p);
  1710.         p = (SpriteInfoRecPtr) p->nextSprite;
  1711.     }
  1712.     return(0L);
  1713. }
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721. SceneryInfoRecPtr FindTwinScenery(short pictID)
  1722. {
  1723.     SceneryInfoRecPtr sc;
  1724.     
  1725.     sc = Sprite_Mgr_Globals->backgrounds;
  1726.     while (sc) {
  1727.         if (sc->pictID == pictID)
  1728.             return(sc);
  1729.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  1730.     }
  1731.     sc = Sprite_Mgr_Globals->foregrounds;
  1732.     while (sc) {
  1733.         if (sc->pictID == pictID)
  1734.             return(sc);
  1735.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  1736.     }
  1737.     return(0L);
  1738. }
  1739.  
  1740.  
  1741.  
  1742.  
  1743.  
  1744.  
  1745. void CheckChangedScenery(SceneryInfoRecPtr scenery)
  1746. {
  1747.     SceneryInfoRecPtr sc = scenery;
  1748.     Rect box, dRect;
  1749.  
  1750.     while (sc) {
  1751.         box = sc->sceneryWorld->portRect;
  1752.         if (sc->scrollTicks) {
  1753.             if (sc->nextTickCount <= TickCount()) {
  1754.                 sc->scrollOffset.v += sc->autoScrollAmount.v;
  1755.                 sc->scrollOffset.h += sc->autoScrollAmount.h;
  1756.                 sc->nextTickCount = TickCount() + sc->scrollTicks;
  1757.                 sc->changed = true;
  1758.                 Sprite_Mgr_Globals->redoCheck = true;
  1759.                 if (sc->scrollOffset.v >= box.bottom)
  1760.                     sc->scrollOffset.v = 0;
  1761.                 if (sc->scrollOffset.h >= box.right)
  1762.                     sc->scrollOffset.h = 0;            // wrap around...
  1763.             }
  1764.         }
  1765.         if (sc->changed && (sc->hidden == false)) {
  1766.             
  1767.             dRect = sc->animationRect;
  1768.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites);
  1769.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites);
  1770.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites);
  1771.             MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds);
  1772.             MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds);
  1773.         }
  1774.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  1775.     }
  1776. }
  1777.  
  1778.  
  1779.  
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.  
  1787.  
  1788.  
  1789. void CheckChangedSprite(SpriteInfoRecPtr sprite)
  1790. {
  1791.     SpriteInfoRecPtr p = sprite;
  1792.     Rect dRect;
  1793.  
  1794.     while (p) {
  1795.         if (p->tickWait) {
  1796.             if (p->lastTick <= TickCount()) {
  1797.                 p->currentFace++;
  1798.                 if (p->currentFace > p->faces)
  1799.                     p->currentFace = 1;
  1800.                 p->lastTick = TickCount() + p->tickWait;
  1801.                 p->changed = true;
  1802.                 Sprite_Mgr_Globals->redoCheck = true;
  1803.             }
  1804.         }
  1805.         if (p->changed && (p->hidden == false)) {
  1806.             dRect = p->animationRect;
  1807.             MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds);
  1808.             MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds);
  1809.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites);
  1810.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites);
  1811.             MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites);
  1812.             if (p->oldAnimationRect.right != 0) {
  1813.                 dRect = p->oldAnimationRect;
  1814.                 MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds);
  1815.                 MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds);
  1816.                 MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites);
  1817.                 MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites);
  1818.                 MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites);
  1819.                 p->oldAnimationRect.right = 0;
  1820.             }
  1821.         }
  1822.         p = (SpriteInfoRecPtr) p->nextSprite;
  1823.     }
  1824. }
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835.  
  1836.  
  1837. void UpdateScenery(SceneryInfoRecPtr scenery)
  1838. {
  1839.     SceneryInfoRecPtr sc = scenery;
  1840.     Rect sRect, dRect;
  1841.     WindowPtr g1, g2;
  1842.     short h, v;
  1843.     Boolean fits;
  1844.  
  1845.     while (sc) {
  1846.         if (sc->changed && (sc->hidden == false)) {
  1847.             sc->changed = false;
  1848.             fits = true;
  1849.             Sprite_Mgr_Globals->changed = true;
  1850.             
  1851.             sRect = sc->sceneryRect;
  1852.             dRect = sc->animationRect;
  1853.             if (Sprite_Mgr_Globals->updateRects < kMaxUR) {
  1854.                 Sprite_Mgr_Globals->changedRect[Sprite_Mgr_Globals->updateRects] = dRect;
  1855.                 Sprite_Mgr_Globals->updateRects++;
  1856.             }
  1857.             v = dRect.bottom - dRect.top;
  1858.             h = dRect.right - dRect.left;
  1859.             if (sRect.right > h)                 // is destination smaller ?
  1860.                 sRect.right = sRect.left + h;    // make source smaller
  1861.             if (sRect.bottom > v)
  1862.                 sRect.bottom = sRect.top + v;
  1863.             
  1864.             sRect.top += sc->scrollOffset.v;
  1865.             sRect.bottom += sc->scrollOffset.v;        // add scroll offsets
  1866.             sRect.left += sc->scrollOffset.h;
  1867.             sRect.right += sc->scrollOffset.h;
  1868.             g1 = (GrafPtr) sc->sceneryWorld;
  1869.             g2 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld;
  1870.             
  1871.             if ((sRect.bottom - sRect.top) < v)
  1872.                 fits = false;
  1873.             if ((sRect.right - sRect.left) < h)
  1874.                 fits = false;
  1875.             if (fits) {
  1876.                 CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L);
  1877.             }
  1878.             else {            // source has scrolled too much, so compensate
  1879.                 h -= sRect.right - sRect.left;
  1880.                 v -= sRect.bottom - sRect.top;        // get difference
  1881.                 
  1882.                 dRect.right -= h;    // clip to area we already have
  1883.                 dRect.bottom -= v;
  1884.                 sRect.right -= h;
  1885.                 sRect.bottom -= v;
  1886.                 CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L);
  1887.                 
  1888.                 if (h) {
  1889.                     dRect.right += h;    // now get residue at right
  1890.                     dRect.left = dRect.right - h;
  1891.                     sRect.left = sc->sceneryRect.left;
  1892.                     sRect.right = sRect.left + h;
  1893.                     CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L);
  1894.                 }
  1895.                 if (v) {
  1896.                     dRect.bottom += v;    // now get residue at bottom
  1897.                     dRect.top = dRect.bottom - v;
  1898.                     sRect.top = sc->sceneryRect.top;
  1899.                     sRect.bottom = sRect.top + v;
  1900.                     CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L);
  1901.                 }
  1902.             }
  1903.         }
  1904.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  1905.     }
  1906. }
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918.  
  1919. void UpdateSprite(SpriteInfoRecPtr sprite)
  1920. {
  1921.     SpriteInfoRecPtr p = sprite;
  1922.     Rect sRect, dRect;
  1923.     WindowPtr g1, g2;
  1924.  
  1925.     while (p) {
  1926.         if (p->changed && (p->hidden == false)) {
  1927.             p->changed = false;
  1928.             Sprite_Mgr_Globals->changed = true;
  1929.             
  1930.             sRect = p->spriteRect;
  1931.             sRect.left = sRect.right * (p->currentFace - 1);  // get the right face...
  1932.             sRect.right *= p->currentFace;
  1933.             dRect = p->animationRect;
  1934.             if (Sprite_Mgr_Globals->updateRects < kMaxUR) {
  1935.                 Sprite_Mgr_Globals->changedRect[Sprite_Mgr_Globals->updateRects] = dRect;
  1936.                 Sprite_Mgr_Globals->updateRects++;
  1937.             }
  1938.             g1 = (GrafPtr) p->spriteWorld;
  1939.             g2 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld;
  1940.             CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, p->copyMode, 0L);
  1941.         }
  1942.         p = (SpriteInfoRecPtr) p->nextSprite;
  1943.     }
  1944. }
  1945.  
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951.  
  1952.  
  1953. void MarkSceneryInRect(Rect *box, SceneryInfoRecPtr scenery)
  1954. {
  1955.     SceneryInfoRecPtr sc;
  1956.     Rect sRect;
  1957.     Boolean dirty;
  1958.     Point pixel;
  1959.  
  1960.     sc = scenery;
  1961.     while (sc) {
  1962.         if (sc->changed == false) {
  1963.             dirty = false;
  1964.             sRect = sc->animationRect;
  1965.             
  1966.             pixel.h = sRect.left;
  1967.             pixel.v = sRect.top;
  1968.             if (SMgrPtInRect(pixel, box))
  1969.                 dirty = true;
  1970.             if (!dirty) {
  1971.                 pixel.h = sRect.left;
  1972.                 pixel.v = sRect.bottom;
  1973.                 if (SMgrPtInRect(pixel, box))
  1974.                     dirty = true;
  1975.             }
  1976.             if (!dirty) {
  1977.                 pixel.h = sRect.right;
  1978.                 pixel.v = sRect.bottom;
  1979.                 if (SMgrPtInRect(pixel, box))
  1980.                     dirty = true;
  1981.             }
  1982.             if (!dirty) {
  1983.                 pixel.h = sRect.right;
  1984.                 pixel.v = sRect.top;
  1985.                 if (SMgrPtInRect(pixel, box))
  1986.                     dirty = true;
  1987.             }
  1988.             if (!dirty) {
  1989.                 if (RectIntersect(&sRect, box))
  1990.                     dirty = true;
  1991.             }
  1992.             if (dirty) {
  1993.                 sc->changed = true;
  1994.                 Sprite_Mgr_Globals->redoCheck = true;
  1995.             }
  1996.         }
  1997.         sc = (SceneryInfoRecPtr) sc->nextScenery;
  1998.     }
  1999. }
  2000.  
  2001.  
  2002.  
  2003.  
  2004.  
  2005.  
  2006. void MarkSpriteInRect(Rect *box, SpriteInfoRecPtr sprite)
  2007. {
  2008.     SpriteInfoRecPtr p = sprite;
  2009.     Rect sRect;
  2010.     Boolean dirty;
  2011.     Point pixel;
  2012.  
  2013.     while (p) {
  2014.         if (p->changed == false) {
  2015.             dirty = false;
  2016.             sRect = p->animationRect;
  2017.             pixel.h = sRect.left;
  2018.             pixel.v = sRect.top;
  2019.             if (SMgrPtInRect(pixel, box))
  2020.                 dirty = true;
  2021.             if (!dirty) {
  2022.                 pixel.h = sRect.left;
  2023.                 pixel.v = sRect.bottom;
  2024.                 if (SMgrPtInRect(pixel, box))
  2025.                     dirty = true;
  2026.             }
  2027.             if (!dirty) {
  2028.                 pixel.h = sRect.right;
  2029.                 pixel.v = sRect.bottom;
  2030.                 if (SMgrPtInRect(pixel, box))
  2031.                     dirty = true;
  2032.             }
  2033.             if (!dirty) {
  2034.                 pixel.h = sRect.right;
  2035.                 pixel.v = sRect.top;
  2036.                 if (SMgrPtInRect(pixel, box))
  2037.                     dirty = true;
  2038.             }
  2039.             if (!dirty) {
  2040.                 if (RectIntersect(&sRect, box))
  2041.                     dirty = true;
  2042.             }
  2043.             if (dirty) {
  2044.                 p->changed = true;
  2045.                 Sprite_Mgr_Globals->redoCheck = true;
  2046.             }
  2047.         }
  2048.         p = (SpriteInfoRecPtr) p->nextSprite;
  2049.     }
  2050. }
  2051.  
  2052.  
  2053.  
  2054.  
  2055.  
  2056.  
  2057.  
  2058.  
  2059.  
  2060. void CopyGToScreen(void)
  2061. {
  2062.     short id;
  2063.     SpriteInfoRecPtr p = 0L;
  2064.     SceneryInfoRecPtr sc = 0L;
  2065.     Boolean done = false;
  2066.     GrafPtr g1, g2;
  2067.     Rect sRect, dRect;
  2068.     short mode;
  2069.     
  2070.     DebugStr("\pSet ID?");
  2071.     id = 0;
  2072.     p = FindSprite(id);
  2073.     if (!p) {
  2074.         sc = Sprite_Mgr_Globals->backgrounds;
  2075.         while (sc && !done) {
  2076.             if (sc->id == id)
  2077.                 done = true;
  2078.             else
  2079.                 sc = (SceneryInfoRecPtr) sc->nextScenery;
  2080.         }
  2081.         if (!sc) {
  2082.             sc = Sprite_Mgr_Globals->foregrounds;
  2083.             while (sc && !done) {
  2084.                 if (sc->id == id)
  2085.                     done = true;
  2086.                 else
  2087.                     sc = (SceneryInfoRecPtr) sc->nextScenery;
  2088.             }
  2089.         }
  2090.         if (!done)
  2091.             return;
  2092.     }
  2093.     if (p) {
  2094.         g1 = (GrafPtr) p->spriteWorld;
  2095.         dRect = sRect = p->spriteRect;
  2096.         mode = p->copyMode;
  2097.     }
  2098.     else {
  2099.         g1 = (GrafPtr) sc->sceneryWorld;
  2100.         dRect = sRect = sc->sceneryWorld->portRect;
  2101.         mode = sc->copyMode;
  2102.     }
  2103.     g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow;
  2104.     CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, mode, 0L);
  2105.  
  2106. }
  2107.  
  2108.  
  2109.  
  2110.  
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116. Boolean SMgrPtInRect(Point pixel, Rect *box)
  2117. {
  2118.     if (pixel.h < box->left)
  2119.         return(false);
  2120.     if (pixel.h > box->right)
  2121.         return(false);
  2122.     if (pixel.v < box->top)
  2123.         return(false);
  2124.     if (pixel.v > box->bottom)
  2125.         return(false);
  2126.     return(true);
  2127. }
  2128.  
  2129.  
  2130.  
  2131.  
  2132.  
  2133.  
  2134.  
  2135. Boolean RectIntersect(Rect *r, Rect *box)
  2136. {
  2137.     Rect inter; /* register short d;
  2138.     
  2139.     d = 0;
  2140.     if ((r->left > box->left) && (r->left < box->right))
  2141.         d = r->left;
  2142.     if ((box->left > r->left) && (box->left < r->right))
  2143.         d = box->left;
  2144.     if (d == 0)
  2145.         return(false);
  2146.     
  2147.     d = 0;
  2148.     if ((r->top > box->top) && (r->top < box->bottom))
  2149.         d = r->top;
  2150.     if ((box->top > r->top) && (box->top < r->bottom))
  2151.         d = box->top;
  2152.     if (d == 0)
  2153.         return(false);
  2154.     
  2155.     d = 0;
  2156.     if ((r->right < box->right) && (r->right > box->left))
  2157.         d = r->right;
  2158.     if ((box->right < r->right) && (box->right > r->left))
  2159.         d = box->right;
  2160.     if (d == 0)
  2161.         return(false);
  2162.     
  2163.     d = 0;
  2164.     if ((r->bottom < box->bottom) && (r->bottom > box->top))
  2165.         d = r->bottom;
  2166.     if ((box->bottom < r->bottom) && (box->bottom > r->top))
  2167.         d = box->bottom;
  2168.     if (d == 0)
  2169.         return(false); */
  2170.     
  2171.     if (SectRect(r, box, &inter))        // make my own
  2172.         return(true);
  2173.     return(false);
  2174. }
  2175.  
  2176.  
  2177.